/**
 * @desc    页面管理
 * @author  刘贺[of2220]
 * @company qianmi.com
 * @Date    2017/2/10
 */
('use strict');
import PageInfoModel from '../dao/pageInfo/page-info-model';
import TemplateInfoModel from '../dao/templateInfo/template-info-model';
import TemplateInfoSvc from './templateinfo-service';
import GlobalSetupModel from '../dao/globalSetup/global-setup-model';

enum status {
  published,
  notpublished
}
interface pageInfoInterface {
  _id?: string;
  __v?: string;
  siteInfo: any;
  platform: string;
  tplCode: string;
  pageType: string;
  pageCode: string;
  status: status;
  updateTime: any;
  activated?: boolean;
  isDoublePlatformTpl?: boolean;
  pageStyle?: string;
  title: string;
  skinType?: String;
  headLv?: number;
  footLv?: number;
  configOrder: any;
  shareInfo?: { imgSrc?: string; title?: string; desc?: string };
}

export default class PageInfoService {
  static upsertPageInfo(pageInfo: pageInfoInterface): Promise<any> {
    let { pageType, pageCode, platform, siteInfo } = pageInfo;
    if (!pageType || !pageCode || !platform || !siteInfo) {
      throw new Error('参数错误');
    }
    let conditions = { pageType, pageCode, platform, siteInfo };
    let options = { upsert: true };
    delete pageInfo._id;
    delete pageInfo.__v;
    if (pageType !== 'index') {
      delete pageInfo.activated;
    }
    return new Promise((resolve, reject) => {
      PageInfoModel.update(conditions, pageInfo, options).exec((err, res) => {
        err ? reject(err) : resolve(res);
      });
    });
  }

  /**
   * 一键拷贝pageInfo信息
   * @param id
   * @returns {Promise<any>}
   */
  static async copyPageInfo(id): Promise<any> {
    let pageInfo: any = await new Promise((resolve, reject) => {
      PageInfoModel.findById(id).lean().exec((err, data) => {
        err ? reject(err) : resolve(data);
      });
    });
    if (!pageInfo) {
      throw new Error('目标页面不存在');
    }
    let rule4PageCode = await new Promise((resolve, reject) => {
      TemplateInfoModel.findOne({ templateCode: pageInfo.tplCode }).select('rule4PageCode').exec((err, data: any) => {
        err ? reject(err) : resolve(data && data.rule4PageCode);
      });
    });
    if (rule4PageCode !== 'multi') {
      throw new Error(`当前模板rule4PageCode值为${rule4PageCode},不能一键复制`);
    }
    let title = pageInfo.title || '';
    title = !title.includes('[复制]') ? title + '[复制]' : title;
    if (title && _getStrLength(title) > 20) {
      throw new Error('页面名称不能超过20个字符');
    }
    pageInfo.title = title;
    pageInfo.pageCode = Date.now().toString();
    pageInfo.status = 'notpublished';
    pageInfo.updateTime = Date.now();

    if (pageInfo.pageType === 'index') {
      pageInfo.activated = false;
    }
    return await PageInfoService.upsertPageInfo(pageInfo);
  }

  /**
   * 获取页面信息列表  管理页面使用
   * @param siteId
   * @param platform
   * @param includePageTypeList
   * @param excludePageTypeList
   * @param pageNo
   * @param pageSize
   * @returns {Promise<{totalCount: T, pageInfoList: T}>}
   */
  static async getPageInfoList({
    siteId,
    platform = '',
    includePageTypeList = [],
    excludePageTypeList = [],
    pageNo = -1,
    pageSize = 5
  }: {
    siteId: string;
    platform?: string;
    pageTypeList?: string[];
    includePageTypeList?: string[];
    excludePageTypeList?: string[];
    pageNo?: number;
    pageSize?: number;
  }): Promise<{ totalCount: number; pageInfoList: pageInfoInterface[] }> {
    pageNo = parseInt(pageNo + '');
    pageSize = parseInt(pageSize + '');
    let condition = { siteInfo: siteId };
    platform && Object.assign(condition, { platform: platform });
    includePageTypeList &&
      includePageTypeList.length &&
      Object.assign(condition, { pageType: { $in: includePageTypeList } });
    excludePageTypeList &&
      excludePageTypeList.length &&
      Object.assign(condition, { pageType: { $nin: excludePageTypeList } });
    try {
      let totalCount = await PageInfoService.getCount(condition);
      let pageInfoList: any = pageNo == -1
        ? await new Promise((resolve, reject) => {
            PageInfoModel.find(condition)
              .select('-configOrder')
              .sort({ activated: -1, updateTime: -1 })
              .exec((err, data) => {
                err ? reject(err) : resolve(data);
              });
          })
        : await new Promise((resolve, reject) => {
            PageInfoModel.find(condition)
              .select('-configOrder')
              .sort({ activated: -1, updateTime: -1 })
              .skip(pageNo * pageSize)
              .limit(pageSize)
              .exec((err, data) => {
                err ? reject(err) : resolve(data);
              });
          });
      if (pageInfoList && pageInfoList.length) {
        pageInfoList = await populateTemplateInfo(JSON.parse(JSON.stringify(pageInfoList)));
      }
      return { totalCount, pageInfoList };
    } catch (e) {
      throw e;
    }
  }

  /**
   * 获取页面列表 应用页面使用
   * @param siteId
   * @param platform
   * @param includePageTypeList
   * @param excludePageTypeList
   * @param pageNo
   * @param pageSize
   * @returns {Promise<{totalCount: T, pageInfoList: T}>}
   */
  static async getPageList({
    siteId,
    platform = '',
    includePageTypeList = [],
    excludePageTypeList = [],
    pageNo = -1,
    pageSize = 5
  }: {
    siteId: string;
    platform?: string;
    includePageTypeList?: string[];
    excludePageTypeList?: string[];
    pageNo?: number;
    pageSize?: number;
  }): Promise<{ totalCount: number; pageInfoList: pageInfoInterface[] }> {
    pageNo = parseInt(pageNo + '');
    pageSize = parseInt(pageSize + '');
    let condition = { siteInfo: siteId };
    platform && Object.assign(condition, { platform: platform });
    includePageTypeList &&
      includePageTypeList.length &&
      Object.assign(condition, { pageType: { $in: includePageTypeList } });
    excludePageTypeList &&
      excludePageTypeList.length &&
      Object.assign(condition, { pageType: { $nin: excludePageTypeList } });
    Object.assign(condition, {
      $or: [{ pageType: 'index', activated: true }, { status: 'published', pageType: { $ne: 'index' } }]
    });
    try {
      let totalCount = await PageInfoService.getCount(condition);
      let pageInfoList: any = pageNo == -1
        ? await new Promise((resolve, reject) => {
            PageInfoModel.find(condition)
              .select('-configOrder')
              .sort({ activated: -1, updateTime: -1 })
              .exec((err, data) => {
                err ? reject(err) : resolve(data);
              });
          })
        : await new Promise((resolve, reject) => {
            PageInfoModel.find(condition)
              .select('-configOrder')
              .sort({ activated: -1, updateTime: -1 })
              .skip(pageNo * pageSize)
              .limit(pageSize)
              .exec((err, data) => {
                err ? reject(err) : resolve(data);
              });
          });
      return { totalCount, pageInfoList };
    } catch (e) {
      throw e;
    }
  }

  static getCount(condition): Promise<number> {
    return new Promise((resolve, reject) => {
      PageInfoModel.count(condition).exec((err, data) => {
        err ? reject(err) : resolve(data);
      });
    });
  }

  static getPageInfoCount({ siteId, platform, includePageTypeList = [], excludePageTypeList = [] }): Promise<number> {
    let condition = { siteInfo: siteId };
    platform && Object.assign(condition, { platform: platform });
    includePageTypeList &&
      includePageTypeList.length &&
      Object.assign(condition, { pageType: { $in: includePageTypeList } });
    excludePageTypeList &&
      excludePageTypeList.length &&
      Object.assign(condition, { pageType: { $nin: excludePageTypeList } });
    return PageInfoService.getCount(condition);
  }

  static getActivatedPageCode({ siteId, platform }: { siteId: string; platform: string }): Promise<string> {
    let condition = { siteInfo: siteId, activated: true, pageType: 'index', platform };
    return new Promise((resolve, reject) => {
      PageInfoModel.findOne(condition).select('pageCode').lean().exec((err, data: any) => {
        err ? reject(err) : resolve(data && data.pageCode ? data.pageCode : null);
      });
    });
  }

  /**
     * 获取激活首页信息
     * @param siteId
     * @param isComplete 是否获取完整信息
     * @param platform 是否获取指定平台信息
     */
  static async getActivatedPageInfo({
    siteId,
    platform = '',
    isComplete = false
  }: {
    siteId: string;
    isComplete?: boolean;
    platform?: string;
  }): Promise<pageInfoInterface[]> {
    isComplete = typeof isComplete === 'string' ? isComplete === 'true' : isComplete;
    let condition = { siteInfo: siteId, activated: true, pageType: 'index' };
    platform && Object.assign(condition, { platform });
    let pageInfoList: any = !isComplete
      ? await new Promise((resolve, reject) => {
          PageInfoModel.find(condition).select('-configOrder').exec((err, data) => {
            err ? reject(err) : resolve(data);
          });
        })
      : await new Promise((resolve, reject) => {
          PageInfoModel.find(condition).lean().exec((err, data) => {
            err ? reject(err) : resolve(data);
          });
        });
    if (isComplete) {
      pageInfoList = await populateTemplateInfo(pageInfoList);
    }
    return pageInfoList && pageInfoList.length ? JSON.parse(JSON.stringify(pageInfoList)) : [];
  }

  /**
     * pageInfo 全量信息
     */
  static async getDetailPageInfo({ siteId, platform, pageType, pageCode }): Promise<pageInfoInterface> {
    let condition = { siteInfo: siteId, platform, pageType, pageCode };
    let detailPageInfo: any = await new Promise((resolve, reject) => {
      PageInfoModel.findOne(condition).lean().exec((err, data) => {
        err ? reject(err) : resolve(data);
      });
    });
    if (detailPageInfo) {
      detailPageInfo.templateInfo = await TemplateInfoSvc.getTemplateInfoByIdOrCode(detailPageInfo.tplCode);
      return detailPageInfo;
    } else {
      return null;
    }
  }
  /**
     * pageInfo 全量信息 除了 co tplInfo
     */
  static getPageInfo({ siteId, platform, pageType, pageCode }): Promise<pageInfoInterface> {
    let condition = { siteInfo: siteId, platform, pageType, pageCode };
    return new Promise((resolve, reject) => {
      PageInfoModel.findOne(condition).select('-configOrder').exec((err, data: pageInfoInterface) => {
        err ? reject(err) : resolve(data);
      });
    });
  }

  /**
     * 设置所有首页非激活
     * @param siteId
     * @param platform
     * @param pageType
     * @returns {Promise<T>}
     */
  static setUnActivated({ siteId, platform, pageType = 'index' }): Promise<any> {
    let condition = { siteInfo: siteId, platform, pageType };
    return new Promise((resolve, reject) => {
      PageInfoModel.update(condition, { $set: { activated: false } }, { multi: true }, function(err, data) {
        err ? reject(err) : resolve(data);
      });
    });
  }

  static async setActivated({
    siteId,
    platform,
    pageCode,
    pageType = 'index'
  }: {
    siteId: string;
    platform: string;
    pageCode: string;
    pageType?: string;
  }): Promise<any> {
    await PageInfoService.setUnActivated({ siteId, platform, pageType });
    return await new Promise((resolve, reject) => {
      PageInfoModel.findOneAndUpdate(
        {
          siteInfo: siteId,
          platform,
          pageType,
          pageCode
        },
        { $set: { activated: true } }
      ).exec((err, data) => {
        err ? reject(err) : resolve(data);
      });
    });
  }

  /**
   * 更改pageInfo信息
   * @param siteId
   * @param platform
   * @param pageType
   * @param pageCode
   * @param info
   * @returns {Promise<T>}
   */
  static updatePageInfo({ siteId, platform, pageType, pageCode, info }): Promise<pageInfoInterface> {
    let condition = { siteInfo: siteId, platform, pageType, pageCode };
    return new Promise((resolve, reject) => {
      PageInfoModel.findOneAndUpdate(condition, {
        $set: info
      }).exec((err, data: pageInfoInterface) => {
        err ? reject(err) : resolve(data);
      });
    });
  }

  /**
     * 仅获取configOrder
     */
  static getConfigOrder({ siteId, platform, pageType, pageCode }): Promise<any> {
    let condition = {
      siteInfo: siteId,
      platform,
      pageType,
      pageCode
    };
    return new Promise((resolve, reject) => {
      PageInfoModel.findOne(condition).select('configOrder').lean().exec((err, data: any) => {
        err ? reject(err) : resolve(data && data.configOrder ? data.configOrder : null);
      });
    });
  }

  /**
     * 删除页面信息
     */
  static deletePageInfo({ siteId, platform, pageType, pageCode }): Promise<any> {
    let condition = {
      siteInfo: siteId,
      platform,
      pageType,
      pageCode
    };
    return new Promise((resolve, reject) => {
      PageInfoModel.findOneAndRemove(condition).exec((err, data) => {
        err ? reject(err) : resolve(data);
      });
    });
  }

  static getTemplateUsedCount(): Promise<{ count: number; templateCode: string }[]> {
    return new Promise((resolve, reject) => {
      PageInfoModel.aggregate([
        { $group: { _id: { templateCode: '$tplCode' }, count: { $sum: 1 } } },
        { $project: { _id: 0, templateCode: '$_id.templateCode', count: 1 } }
      ]).exec((err, data: any) => {
        err ? reject(err) : resolve(data);
      });
    });
  }

  static async aggregatePageCount({ uid }): Promise<any> {
    let users: any = await new Promise((resolve, reject) => {
      GlobalSetupModel.find({ uid }).select('uid systemCode _id').lean().exec((err, data) => {
        err ? reject(err) : resolve(data);
      });
    });
    let last = {};
    for (let i = 0, len = users.length; i < len; i++) {
      let { uid, systemCode, _id: siteId } = users[i];
      let result = <any>await new Promise((resolve, reject) => {
        PageInfoModel.aggregate([
          { $match: { siteInfo: siteId } },
          { $group: { _id: { platform: '$platform' }, count: { $sum: 1 } } },
          { $project: { _id: 0, platform: '$_id.platform', count: 1 } }
        ]).exec((err, data: any) => {
          err ? reject(err) : resolve(data);
        });
      });
      last[systemCode] = result.reduce((l, c) => {
        l[c.platform] = c.count;
        return l;
      }, {});
    }
    return last;
  }
}

let _getStrLength = str => {
  let reg = /[\u4e00-\u9fa5]/g;
  let chinese = str.match(reg) || [];
  let alphanumeric = str.replace(reg, '') || '';
  return chinese.length * 2 + alphanumeric.length;
};

let populateTemplateInfo = async function(pageInfoList) {
  if (pageInfoList.length && pageInfoList.length > 0) {
    let tplCodeList = [];
    for (let i = 0, len = pageInfoList.length; i < len; i++) {
      let pageInfo = pageInfoList[i];
      !tplCodeList.includes(pageInfo.tplCode) && tplCodeList.push(pageInfo.tplCode);
    }
    let tplInfoList = await TemplateInfoSvc.getTplListByTplCodes(tplCodeList);
    let tplInfoMap = {};
    for (let i = 0, len = tplInfoList.length; i < len; i++) {
      let tplInfo = tplInfoList[i];
      tplInfoMap[tplInfo.templateCode] = tplInfo;
    }
    for (let i = 0, len = pageInfoList.length; i < len; i++) {
      let pageInfo = pageInfoList[i];
      pageInfoList[i].templateInfo = tplInfoMap[pageInfo.tplCode];
    }
  }
  return pageInfoList;
};
